#include "Submodule/EffectItemGenerator.h"

#include "Submodule/MagicItemGenerator.h"
#include "Submodule/Utilities.h"
#include "Submodule/Globals.h"

#include "API/Magic/Magic.h"
#include "API/Magic/EffectSetting.h"
#include "API/Magic/MagicItemForm.h"
#include "API/Settings/Settings.h"
#include "API/Settings/SettingCollection.h"
#include "API/Actors/ActorValues.h"

#include "API/BSTypes/BSStringT.h"

#ifdef OBLIVION
	// GMSTs
	#include "API/Settings/Settings.h"
	#include "API/Settings/SettingCollection.h"

	Setting* EffectItemGenerator::fMagicDurMagBaseCostMult = NULL;
	Setting* EffectItemGenerator::fMagicCostScale = NULL;
	Setting* EffectItemGenerator::fMagicAreaBaseCostMult = NULL;
	Setting* EffectItemGenerator::fMagicRangeTargetCostMult = NULL;

	Setting* EffectItemGenerator::fMagickaReturnBase = NULL;
	Setting* EffectItemGenerator::fMagickaReturnMult = NULL;
#else
	#include "Submodule/ARES.rc.h"
	#include "API/CSDialogs/TESDialog.h"
#endif

#pragma warning(disable : 4996) // sprintf is deprecated

EffectItemGenerator::EffectItemGenerator(EffectSetting* selMgef, int selMinMag, int selMinDur, int selMinAoE, int selEffProp, int selActorVal, MagicItemGenerator* selMig, ScriptEffectInfoGenerator* scriptData)
 : mgef(selMgef)
 , onSelf( selMgef?(selMgef->mgefFlags & EffectSetting::kMgefFlag_OnSelf ) != 0:true)
 , noDurPct( selMgef?((selMgef->mgefFlags & EffectSetting::kMgefFlag_NoDuration) != 0)?100:0:0 ), noAoEPct(100)
 , minMag(selMinMag), minDur(selMinDur), minAoE(selMinAoE)
 , effProp(selEffProp)
 , actorVal(selActorVal)
 , mig(selMig)
 , seff(scriptData)
{
	if ( mgef ) {
		_VMESSAGE("Constructing EffectItemGenerator '%4.4s' from scratch.", &mgef->mgefCode);
	}
	else {
		_VMESSAGE("Constructing EffectItemGenerator from scratch; mgef null.");
	}

#ifdef OBLIVION
	if ( static bool runonce = true ) {
		if ( !GameSettingCollection::GameSettings.settingMap.GetAt("fMagicDurMagBaseCostMult", fMagicDurMagBaseCostMult) )
			fMagicDurMagBaseCostMult = NULL;
		if ( !GameSettingCollection::GameSettings.settingMap.GetAt("fMagicCostScale", fMagicCostScale) )
			fMagicCostScale = NULL;
		if ( !GameSettingCollection::GameSettings.settingMap.GetAt("fMagicAreaBaseCostMult", fMagicAreaBaseCostMult) )
			fMagicAreaBaseCostMult = NULL;
		if ( !GameSettingCollection::GameSettings.settingMap.GetAt("fMagicRangeTargetCostMult", fMagicRangeTargetCostMult) )
			fMagicRangeTargetCostMult = NULL;
		if ( !GameSettingCollection::GameSettings.settingMap.GetAt("fMagickaReturnBase", fMagickaReturnBase) )
			fMagickaReturnBase = NULL;
		if ( !GameSettingCollection::GameSettings.settingMap.GetAt("fMagickaReturnMult", fMagickaReturnMult) )
			fMagickaReturnMult = NULL;
		runonce = false;
	}
#endif
}
/*
EffectItemGenerator::EffectItemGenerator(std::stringstream& str) {
	loadSaveString(str);
	if ( mgef ) {
		_MESSAGE("Constructing EffectItemGenerator '%4.4s' from save stream.", &mgef->mgefCode);
	}
	else {
		_MESSAGE("Constructing EffectItemGenerator from save stream; mgef null.");
	}
}
*/
EffectItemGenerator::EffectItemGenerator(const EffectItemGenerator& copied) :
/*	mgef(copied.mgef),
	onSelf(copied.onSelf).
	noVars(copied.noVars),
	noDurPct(copied.noDurPct),
	minMag(copied.minMag),
	minDur(copied.minDur),
	effProp(copied.effProp),
	actorVal(copied.actorVal),*/
	seff(NULL)
{
	if ( mgef ) {
		_VMESSAGE("Constructing EffectItemGenerator '%4.4s' by copy.", &mgef->mgefCode);
	}
	else {
		_VMESSAGE("Constructing EffectItemGenerator by copy; mgef null.");
	}
	mgef = copied.mgef;
	onSelf = copied.onSelf;
	noDurPct = copied.noDurPct;
	minMag = copied.minMag;
	minDur = copied.minDur;
	effProp = copied.effProp;
	actorVal = copied.actorVal;
	if ( copied.mig )
		mig = copied.mig;
	if ( copied.seff )
		seff = new ScriptEffectInfoGenerator(*copied.seff);
}

EffectItemGenerator::~EffectItemGenerator() {
	if ( seff )
		delete seff;
}

bool operator==(const EffectItemGenerator::ScriptEffectInfoGenerator& left, const EffectItemGenerator::ScriptEffectInfoGenerator& right) {
	if ( &left == &right )
		return true;
	return ( left.scriptFormID == right.scriptFormID && left.name == right.name && left.school == right.school && left.fxMgefCode == right.fxMgefCode && left.hostile == right.hostile && left.baseCost == right.baseCost && left.barterFactor == right.barterFactor && left.enchantFactor == right.enchantFactor && left.noAoE == right.noAoE && left.noDur == right.noDur && left.noMag == right.noMag );
}

bool operator!=(const EffectItemGenerator::ScriptEffectInfoGenerator& left, const EffectItemGenerator::ScriptEffectInfoGenerator& right) {
	if ( &left == &right )
		return false;
	return !(left==right);
}

bool EffectItemGenerator::operator==(const EffectItemGenerator& right) const {
	if ( this == &right )
		return true;
	return ( mgef == right.mgef && onSelf == right.onSelf && noDurPct == right.noDurPct && minMag == right.minMag && minDur == right.minDur && effProp == right.effProp && actorVal == right.actorVal && ( (!seff && !right.seff) || (seff && right.seff && *seff == *right.seff) ) );
}

bool EffectItemGenerator::operator!=(const EffectItemGenerator& right) const {
	if ( this == &right )
		return false;
	return !operator==(right);
}

EffectItemGenerator& EffectItemGenerator::operator=(const EffectItemGenerator& right) {
	mgef = right.mgef;
	onSelf = right.onSelf;
	noDurPct = right.noDurPct;
	minMag = right.minMag;
	minDur = right.minDur;
	effProp = right.effProp;
	actorVal = right.actorVal;
	if ( seff )
		delete seff;
	if ( right.seff )
		seff = new ScriptEffectInfoGenerator(*right.seff);
	else
		seff = NULL;
	return *this;
}

BSStringT EffectItemGenerator::GetEffectName() const {
	if ( mgef->mgefCode == Swap32('SEFF') && seff )
		return GetScriptEffectName();
	else
		return mgef->name;
}

UInt32 EffectItemGenerator::GetEffectSchool() const {
	if ( mgef->mgefCode == Swap32('SEFF') && seff )
		return GetScriptEffectSchool();
	else
		return mgef->school;
}

bool EffectItemGenerator::IsHostile() const {
	if ( mgef->mgefCode == Swap32('SEFF') && seff )
		return GetScriptEffectIsHostile();
	else
		return (mgef->mgefFlags & EffectSetting::kMgefFlag_Hostile) != 0;
}

bool EffectItemGenerator::HasMagnitude() const {
	return !(mgef->mgefFlags & EffectSetting::kMgefFlag_NoMagnitude) || (mgef->mgefCode == Swap32('SEFF') && seff && !seff->noMag);
}

bool EffectItemGenerator::HasDuration() const {
	return !(mgef->mgefFlags & EffectSetting::kMgefFlag_NoDuration) || (mgef->mgefCode == Swap32('SEFF') && seff && !seff->noDur);
}

bool EffectItemGenerator::HasArea() const {
	return !(mgef->mgefFlags & EffectSetting::kMgefFlag_NoArea) || (mgef->mgefCode == Swap32('SEFF') && seff && !seff->noAoE);
}

float EffectItemGenerator::GetEffectBaseCost() const {
	if ( mgef->mgefCode == Swap32('SEFF') && seff )
		return GetScriptEffectBaseCost();
	else
		return mgef->baseCost;
}

float EffectItemGenerator::GetEffectEnchantFactor() const {
	if ( mgef->mgefCode == Swap32('SEFF') && seff )
		return GetScriptEffectEnchantFactor();
	else
		return mgef->enchantFactor;
}

float EffectItemGenerator::GetEffectBarterFactor() const {
	if ( mgef->mgefCode == Swap32('SEFF') && seff )
		return GetScriptEffectBarterFactor();
	else
		return mgef->enchantFactor;
}

bool EffectItemGenerator::GetIsOnSelf() const {
	return onSelf;
}

bool EffectItemGenerator::SetIsOnSelf(bool new_on_self) {
	onSelf = new_on_self;
	return true;
}

UInt8 EffectItemGenerator::GetNoDurationChance() const {
	return noDurPct;
}

bool EffectItemGenerator::SetNoDurationChance(UInt8 new_no_dur_pct) {
	noDurPct = new_no_dur_pct;
	return true;
}

UInt8 EffectItemGenerator::GetMinimumMagnitude() const {
	return minMag;
}

bool EffectItemGenerator::SetMinimumMagnitude(UInt8 new_min_mag) {
	minMag = new_min_mag;
	return true;
}

UInt8 EffectItemGenerator::GetMinimumDuration() const {
	return minDur;
}

bool EffectItemGenerator::SetMinimumDuration(UInt8 new_min_dur) {
	minDur = new_min_dur;
	return true;
}

UInt8 EffectItemGenerator::GetMinimumArea() const {
	return minAoE;
}

bool EffectItemGenerator::SetMinimumArea(UInt8 new_min_aoe) {
	minAoE = new_min_aoe;
	return true;
}

UInt8 EffectItemGenerator::GetEffectProportion() const {
	return effProp;
}

bool EffectItemGenerator::SetEffectProportion(UInt8 new_eff_prop) {
	effProp = new_eff_prop;
	return true;
}

UInt8 EffectItemGenerator::GetActorValue() const {
	return actorVal;
}

bool EffectItemGenerator::SetActorValue(UInt8 new_actor_val) {
	actorVal = new_actor_val;
	return true;
}

UInt32 EffectItemGenerator::GetMagicEffect() const {
	if ( !mgef )
		return 0;
	return mgef->formID;
}

bool EffectItemGenerator::SetMagicEffect(EffectSetting* new_mgef) {
	mgef = new_mgef;
	if ( mgef->formID == Swap32('SEFF') && !seff )
		seff = new ScriptEffectInfoGenerator();
	else if ( mgef->formID != Swap32('SEFF') && seff )
		delete seff;
	return true;
}

UInt32 EffectItemGenerator::GetScriptEffectScript() const {
	if ( !seff )
		return 0;
	return seff->scriptFormID;
}

bool EffectItemGenerator::SetScriptEffectScript(UInt32 new_script_form_id) {
	if ( mgef->formID != Swap32('SEFF') )
		return false;
	if ( !seff )
		seff = new ScriptEffectInfoGenerator();
/*	Script* scriptObj = dynamic_cast<Script*>(TESForm::LookupByFormID(new_script_form_id));
	if ( !scriptObj )
		return false;
*/	seff->scriptFormID = new_script_form_id;
	return true;
}

BSStringT EffectItemGenerator::GetScriptEffectName() const {
	if ( !seff )
		return "";
	return seff->name;
}

bool EffectItemGenerator::SetScriptEffectName(const BSStringT& new_seff_name) {
	if ( mgef->formID != Swap32('SEFF') )
		return false;
	if ( !seff )
		seff = new ScriptEffectInfoGenerator();
	seff->name = new_seff_name;
	return true;
}

UInt32 EffectItemGenerator::GetScriptEffectSchool() const {
	if ( !seff )
		return -1;
	return seff->school;
}

bool EffectItemGenerator::SetScriptEffectSchool(UInt32 new_seff_school) {
	if ( mgef->formID != Swap32('SEFF') )
		return false;
	if ( !seff )
		seff = new ScriptEffectInfoGenerator();
	seff->school = new_seff_school;
	return true;
}

UInt32 EffectItemGenerator::GetScriptEffectVisuals() const {
	if ( !seff )
		return 0;
	return seff->fxMgefCode;
}

bool EffectItemGenerator::SetScriptEffectVisuals(UInt32 new_seff_vis) {
	if ( mgef->formID != Swap32('SEFF') )
		return false;
	if ( !seff )
		seff = new ScriptEffectInfoGenerator();
	EffectSetting* vis = EffectSetting::LookupByCode(new_seff_vis);
	if ( !vis )
		return false;
	seff->fxMgefCode = new_seff_vis;
	return true;
}

bool EffectItemGenerator::GetScriptEffectIsHostile() const {
	if ( !seff )
		return false;
	return seff->hostile;
}

bool EffectItemGenerator::SetScriptEffectIsHostile(bool new_seff_hostile) {
	if ( mgef->formID != Swap32('SEFF') )
		return false;
	if ( !seff )
		seff = new ScriptEffectInfoGenerator();
	seff->hostile = new_seff_hostile;
	return true;
}

bool EffectItemGenerator::GetScriptEffectHasMagnitude() const {
	if ( !seff )
		return false;
	return !seff->noMag;
}

bool EffectItemGenerator::SetScriptEffectHasMagnitude(bool new_seff_has_mag) {
	if ( mgef->formID != Swap32('SEFF') )
		return false;
	if ( !seff )
		seff = new ScriptEffectInfoGenerator();
	seff->noMag = !new_seff_has_mag;
	return true;
}

bool EffectItemGenerator::GetScriptEffectHasDuration() const {
	if ( !seff )
		return false;
	return !seff->noDur;
}

bool EffectItemGenerator::SetScriptEffectHasDuration(bool new_seff_has_dur) {
	if ( mgef->formID != Swap32('SEFF') )
		return false;
	if ( !seff )
		seff = new ScriptEffectInfoGenerator();
	seff->noDur = !new_seff_has_dur;
	return true;
}

float EffectItemGenerator::GetScriptEffectBaseCost() const {
	if ( !seff )
		return -1;
	return seff->baseCost;
}

bool EffectItemGenerator::SetScriptEffectBaseCost(float new_seff_base_cost) {
	if ( mgef->formID != Swap32('SEFF') )
		return false;
	if ( !seff )
		seff = new ScriptEffectInfoGenerator();
	seff->baseCost = new_seff_base_cost;
	return true;
}

float EffectItemGenerator::GetScriptEffectEnchantFactor() const {
	if ( !seff )
		return -1;
	return seff->enchantFactor;
}

bool EffectItemGenerator::SetScriptEffectEnchantFactor(float new_seff_ench) {
	if ( mgef->formID != Swap32('SEFF') )
		return false;
	if ( !seff )
		seff = new ScriptEffectInfoGenerator();
	seff->enchantFactor = new_seff_ench;
	return true;
}

float EffectItemGenerator::GetScriptEffectBarterFactor() const {
	if ( !seff )
		return -1;
	return seff->barterFactor;
}

bool EffectItemGenerator::SetScriptEffectBarterFactor(float new_seff_barter) {
	if ( mgef->formID != Swap32('SEFF') )
		return false;
	if ( !seff )
		seff = new ScriptEffectInfoGenerator();
	seff->barterFactor = new_seff_barter;
	return true;
}
/*
std::string EffectItemGenerator::getSaveString() const {
	std::stringstream str = std::stringstream(std::ios::binary|std::ios::in|std::ios::out);
	str << mgef->mgefCode << onSelf << noVars << noDurPct << minMag << minDur << effProp << actorVal;
	//_VMESSAGE("Save string formed: '%s'.", str.str().c_str());
	return str.str();
}

void EffectItemGenerator::loadSaveString(std::stringstream& str) {
	UInt32 mgefCode;
	str >> mgefCode >> onSelf >> noVars >> noDurPct >> minMag >> minDur >> effProp >> actorVal;
	mgef = EffectSetting::LookupByCode(mgefCode);
	//_VMESSAGE("Save string loaded: MGEF '%4.4s', onSelf %b, noVars %b, noDurPct %i, minMag %i, minDur %i, AV %i.", &mgefCode, onSelf, noVars, noDurPct, minMag, minDur, effProp, actorVal);
}
*/

#ifdef OBLIVION

double getMgefAltConstFactor(UInt32 code) {
	UInt16* pre = (UInt16*)&code;
	EffectSetting* alt = NULL;
	switch (Swap16(*pre)) {
		case 'DG':
			_VMESSAGE("Damage");
			*pre = Swap16('RE');
			break;

		case 'DR':
			_VMESSAGE("Drain");
			*pre = Swap16('FO');
			break;

		case 'WK':
			_VMESSAGE("Weakness");
			*pre = Swap16('RS');
			break;

		default:
			if ( Swap32(code) == 'STMA' ) { // Stunted Magicka is special case;
				// calculate based on how much RESP would replace natural regen
				// assume average (50) Intelligence and Willpower, and no bonuses to Magicka
				if ( !EffectItemGenerator::fMagickaReturnBase || !EffectItemGenerator::fMagickaReturnMult )
					return 0;
				
				float fMagickaReturnBase = EffectItemGenerator::fMagickaReturnBase->value.f;
				float fMagickaReturnMult = EffectItemGenerator::fMagickaReturnMult->value.f;

				double regen = fMagickaReturnBase + fMagickaReturnMult * 50; // 50 for "average" Willpower

				EffectSetting* RESP = EffectSetting::LookupByCodeString("RESP");
				if ( !RESP )
					return 0;

				return regen * RESP->enchantFactor;
			}
			else {
				_VMESSAGE("'%4.4s' does not have an alternate source.", &code);
				return 0;
			}
	}
	alt = EffectSetting::LookupByCode(code);
	if ( alt )
		return alt->enchantFactor;
	else
		return 0;
}

bool EffectItemGenerator::DetermineMagDurAoEPct(double& magPct, double& durPct, double& aoePct) const {
	bool hasMag = HasMagnitude();

	bool hasDur = HasDuration();
	if ( hasDur && noDurPct > 0 ) {
		if ( noDurPct >= 100 )
			hasDur = false;
		else {
			if ( pct() <= noDurPct )
				hasDur = false;
		}
	}
	
	bool hasAoE = HasArea();
	if ( hasAoE && noAoEPct > 0 ) {
		if ( noAoEPct >= 100 )
			hasAoE = false;
		else {
			if ( pct() <= noAoEPct )
				hasAoE = false;
		}
	}
//	_VMESSAGE("%s mag, %s dur, %s aoe.", hasMag?"Has":"Does not have", hasDur?"has":"does not have", hasAoE?"has":"does not have");
	
	magPct = (hasMag?minMag:0);
	durPct = (hasDur?minDur:0);
	aoePct = (hasAoE?minAoE:0);
	if ( magPct + durPct + aoePct < 100 ) {
//		_VMESSAGE("Determining magnitude ratio");
		if ( hasMag ) {
//			_VMESSAGE("Has mag.");
			UInt8 maxMag = 100 - (durPct + aoePct);
			if ( minMag == maxMag )
				magPct = minMag;
			else {
//				_VMESSAGE("Min: %i%%, Max: %i%%", minMag, maxMag);
				boost::uniform_real<double> magRng(minMag, maxMag);
//				_VMESSAGE("Range [%i%%, %i%%] constructed.", minMag, maxMag);
				boost::variate_generator<boost::mt19937&, boost::uniform_real<double> > genMag(rng, magRng);
//				_VMESSAGE("RNG set up.");
				magPct = genMag();
//				_VMESSAGE("Mag generated: %0.1f%%", magPct);
			}
		}
		
//		_VMESSAGE("Determining duration ratio");
		if ( hasDur ) {
//			_VMESSAGE("Has dur.");
			UInt8 maxDur = 100 - (magPct + aoePct);
			if ( minDur == maxDur )
				durPct = minDur;
			else {
//				_VMESSAGE("Min: %i%%, Max: %i%%", minDur, maxDur);
				boost::uniform_real<double> DurRng(minDur, maxDur);
//				_VMESSAGE("Range [%i%%, %i%%] constructed.", minDur, maxDur);
				boost::variate_generator<boost::mt19937&, boost::uniform_real<double> > genDur(rng, DurRng);
//				_VMESSAGE("RNG set up.");
				durPct = genDur();
//				_VMESSAGE("Dur generated: %0.1f%%", durPct);
			}
		}
		
//		_VMESSAGE("Determining area ratio");
		if ( hasAoE ) {
//			_VMESSAGE("Has AoE.");
			UInt8 maxAoE = 100 - (magPct + durPct);
			if ( minAoE == maxAoE )
				aoePct = minAoE;
			else {
//				_VMESSAGE("Min: %i%%, Max: %i%%", minAoE, maxAoE);
				boost::uniform_real<double> aoeRng(minAoE, maxAoE);
//				_VMESSAGE("Range [%i%%, %i%%] constructed.", minAoE, maxAoE);
				boost::variate_generator<boost::mt19937&, boost::uniform_real<double> > genAoE(rng, aoeRng);
//				_VMESSAGE("RNG set up.");
				aoePct = genAoE();
//				_VMESSAGE("AoE generated: %0.1f%%", aoePct);
			}
		}
	}
	double div = magPct + durPct + aoePct;
	magPct /= div;
	durPct /= div;
	aoePct /= div;

	_VMESSAGE("Mag: %0.1f%%, Dur: %0.1f%%, AoE: %0.1f%%", magPct*100, durPct*100, aoePct*100);
	return true;
}

bool EffectItemGenerator::DetermineMagDurAoE(EffectItem* ei, UInt32 cost, double& magPct, double& durPct, double& aoePct) const {
	// cost = baseFactor * constFactor * magFactor * durFactor * aoeFactor * rngFactor

	// baseFactor = mgef->baseCost * fMagicDurMagBaseCostMult
	// constFactor= mgef->enchantFactor
	// magFactor  = mag ^ fMagicCostScale
	// durFactor  = dur
	// aoeFactor  = aoe * fMagicAreaBaseCostMult
	// rngFactor  = OnTarget ? fMagicRangeTargetCostMult : 1
	
	if ( magPct + durPct + aoePct < 0.99 ) {
		_ERROR("Ratios do not add up.");
		return false;
	}

	float seffBase, seffEnch, seffBarter;
	if ( mgef->mgefCode == Swap32('SEFF') ) {
		if ( seff ) {
			seffBase = mgef->baseCost;
			seffEnch = mgef->enchantFactor;
			seffBarter = mgef->barterFactor;
			mgef->baseCost = GetEffectBaseCost();
			mgef->enchantFactor = GetEffectEnchantFactor();
			mgef->barterFactor = GetEffectBarterFactor();
		}
		else
			return false;
	}

	for ( UInt16 i = 1; ei->MagickaCost() < cost; ++i ) {
		ei->SetMagnitude(i*magPct);
		ei->SetDuration(i*durPct);
		ei->SetArea(i*aoePct);
	}

	if ( mgef->mgefCode == Swap32('SEFF') ) {
		mgef->baseCost = seffBase;
		mgef->enchantFactor = seffEnch;
		mgef->barterFactor = seffBarter;
	}

	return true;
}

UInt16 EffectItemGenerator::GenerateEffectItem(EffectItem*& ei, UInt8 soul, Magic::RangeTypes range) const {
	if ( !fMagicDurMagBaseCostMult || !fMagicCostScale || !fMagicAreaBaseCostMult || !fMagicRangeTargetCostMult ) {
		_ERROR("GMSTs necessary to calculate effect statistics are NULL.");
		return 0; // basically, I refuse to guess.
	}

	if ( !mgef || !mgef->formID ) {
		_ERROR("EffectItemGenerator &lt;%p&gt; has an invalid MGEF.");
		return 0;
	}
	
	SInt32 charge = 0;

	ei = new EffectItem(*mgef);
	ei->SetRange(range);
	
	if ( range == Magic::kRange_Self ) {
		_VMESSAGE("Constant effect: '%4.4s'.", &mgef->mgefCode);
		double ceFactor = GetEffectEnchantFactor();
		if ( ceFactor <= 0 )
			ceFactor = getMgefAltConstFactor(mgef->mgefCode);
		if ( ceFactor <= 0 ) {
			_ERROR("MGEF '%4.4s' &lt;%p&gt; has no Constant Effect Enchant Factor; cannot create constant enchantment.", &mgef->mgefCode, mgef->mgefCode);
			delete ei;
			ei = NULL;
			return 0;
		}
		double mult = GetEffectBaseCost() * ceFactor;
		SInt32 minMag, minChrg, maxMag, maxChrg;
		if ( soul > Souls::kSoulIndex_Subpetty && soul < Souls::kSoulIndex_Negative ) {
			minMag = mult*(soul-1)+1;
			minChrg = kSouls->getVl(soul-1);
			maxMag = mult*soul;
			maxChrg = kSouls->getVl(soul);
		}
		else {
			minMag = mult*0.25;
			minChrg = kSouls->getVl(soul)/2;
			maxMag = mult*0.5;
			maxChrg = kSouls->getVl(soul);
		}
		SInt32 mag;

		if ( minMag < maxMag ) {
			boost::uniform_int<UInt16> magRange(minMag, maxMag);
			boost::variate_generator<boost::mt19937, boost::uniform_int<UInt16> > genMag(rng, magRange);

			mag = genMag();
			if ( mag <= 1 ) {
				mag = 1;
				if ( mag > maxMag ) {
					_WARNING("Soul %i insufficient for even magnitude 1 constant enchantment with MGEF '%4.4s' &lt;%p&gt;.", soul, &mgef->mgefCode, mgef->mgefCode);
					delete ei;
					ei = NULL;
					return 0;
				}
			}
			charge = ((mag-minMag)/(maxMag-minMag))*(maxChrg-minChrg)+minChrg;
		}
		else if ( minMag >= 1 ) {
			mag = minMag;
			charge = minChrg;
		}
		else {
			_WARNING("Soul %i insufficient for even magnitude 1 constant enchantment with MGEF '%4.4s' &lt;%p&gt;.", soul, &mgef->mgefCode, mgef->mgefCode);
			delete ei;
			ei = NULL;
			return 0;
		}

		ei->SetMagnitude(mag);
		ei->SetDuration(1);
		ei->SetArea(0);
	}
	else {
		_VMESSAGE("Charged effect: '%4.4s'.", &mgef->mgefCode);
		UInt16 uses;
		boost::uniform_int<UInt16> useRange(mig->minUses, mig->maxUses);
		boost::variate_generator<boost::mt19937&, boost::uniform_int<UInt16> > genUse(rng, useRange);
		uses = genUse();
		_VMESSAGE("%i uses.", uses);

		{ // series of variables limited to local scope
			SInt32 a;
			if ( soul > Souls::kSoulIndex_Subpetty && soul < Souls::kSoulIndex_Negative )
				a = kSouls->getVl(soul-1)+1;
			else
				a = kSouls->getVl(soul)/2;
			SInt32 b = kSouls->getVl(soul);
			if ( a > b ) {
				_ERROR("Soul %i has value %i, greater than soul %i with value %i.", soul-1, a, soul, b);
				delete ei;
				ei = NULL;
				return 0;
			}
			boost::uniform_int<SInt32> chrgRange (a, b);
			boost::variate_generator<boost::mt19937&, boost::uniform_int<SInt32> > chrgGen(rng, chrgRange);
			charge = chrgGen();
		}
		_VMESSAGE("%i charge.", charge);

		if ( charge <= 0 ) {
			_ERROR("MagicItemGenerator &lt;%p&gt; has generated a charge capacity of %i; must be greater than zero.", mig->formID, charge);
			delete ei;
			ei = NULL;
			return 0;
		}
	
		UInt16 cost = charge/uses;
		if ( cost == 0 ) {
			cost = 1;
			charge = kSouls->getVl(soul);
			if ( uses > charge ) {
				uses = charge;
			}
			else {
				charge = cost*uses;
			}
			_VMESSAGE("Resulted in zero cost; forced min 1 cost, changed total charge to %i and total uses to %i.", charge, uses);
		}
		else {
			_VMESSAGE("%i cost.", cost);
		}
	
		if (
				((mgef->mgefFlags & EffectSetting::kMgefFlag_NoArea) == 0)
			 ||	((mgef->mgefFlags & EffectSetting::kMgefFlag_NoDuration) == 0)
			 ||	((mgef->mgefFlags & EffectSetting::kMgefFlag_NoMagnitude) == 0)
		   )
		{
			double magPct;
			double durPct;
			double aoePct;
			if ( !DetermineMagDurAoEPct(magPct, durPct, aoePct) ) { // currently always returns true but nothing wrong with being ready for things
				delete ei;
				ei = NULL;
				return 0;
			}
			if ( !DetermineMagDurAoE(ei, cost, magPct, durPct, aoePct) ) {
				delete ei;
				ei = NULL;
				return 0;
			}
		}
	}

	if ( mgef->mgefFlags & EffectSetting::kMgefFlag_UseAttribute ) {
		if ( actorVal < ActorValues::kActorVal__MAX_Attribute ) {
			ei->actorValue = actorVal;
			_DMESSAGE("Setting AV to predefined attribute: %i", actorVal);
		}
		else {
			boost::uniform_int<UInt32> avRng(ActorValues::kActorVal_Strength, ActorValues::kActorVal_Luck);
			boost::variate_generator<boost::mt19937, boost::uniform_int<UInt32> > genAV(rng, avRng);
			
			ei->actorValue = genAV();
			_DMESSAGE("Set AV to random attribute: %i", ei->actorValue);
		}
	}
	else if ( mgef->mgefFlags & EffectSetting::kMgefFlag_UseSkill ) {
		if ( ActorValues::kActorVal_Armorer <= actorVal && actorVal < ActorValues::kActorVal__MAX_Skill ) {
			ei->actorValue = actorVal;
			_DMESSAGE("Setting AV to predefined skill: %i", actorVal);
		}
		else {
			boost::uniform_int<UInt32> avRng(ActorValues::kActorVal_Armorer, ActorValues::kActorVal_Speechcraft);
			boost::variate_generator<boost::mt19937, boost::uniform_int<UInt32> > genAV(rng, avRng);
			
			ei->actorValue = genAV();
			_DMESSAGE("Set AV to random skill: %i", ei->actorValue);
		}
	}
	else {
		_DMESSAGE("Does not use extra data.");
		ei->actorValue = ActorValues::kActorVal__NONE;
	}

	if ( mgef->formID == Swap32('SEFF') && seff ) // do I really even want to go here? with OBME, this basically shouldn't be used...
		if ( ei->scriptInfo )
			*ei->scriptInfo = *seff;
		else
			ei->scriptInfo = new ScriptEffectInfoGenerator(*seff);

	return charge;
}

#else // #ifndef OBLIVION
EffectItemGenerator* EffectItemGenerator::currPtr = NULL;

UInt8 EffectItemGenerator::SetEffectSettingInDialog(HWND hwndDlg, EffectSetting* newMgef) {
	HWND cbMGEF = GetDlgItem(hwndDlg, ID_MGEF);
	TESComboBox::SetCurSelByData(cbMGEF, (void*)newMgef);

	bool en = !((SendDlgItemMessage(hwndDlg, ID_RANGE, CB_GETCURSEL, 0, 0) == 0) || (newMgef->mgefFlags & EffectSetting::kMgefFlag_NoMagnitude) || (newMgef->mgefFlags & EffectSetting::kMgefFlag_NoDuration));
	if ( !en && newMgef->mgefCode == Swap32('SEFF') )
		en = IsDlgButtonChecked(hwndDlg, IDC_SEFF_MAG) == BST_CHECKED && IsDlgButtonChecked(hwndDlg, IDC_SEFF_DUR) == BST_CHECKED;

	HWND ob = GetDlgItem(hwndDlg, ID_NODURPCT);
	EnableWindow(ob, en);

	ob = GetDlgItem(hwndDlg, ID_MINMAG);
	EnableWindow(ob, en);

	ob = GetDlgItem(hwndDlg, ID_MINDUR);
	EnableWindow(ob, en);

	HWND cbAV = GetDlgItem(hwndDlg, ID_ACTORVAL);
	TESComboBox::Clear(cbAV);
	if ( newMgef->mgefFlags & EffectSetting::kMgefFlag_UseAttribute ) {
		TESComboBox::PopulateWithAttributes(cbAV, true);
		TESComboBox::SetCurSelByData(cbAV, (void*)currPtr->actorVal);
	}
	else if ( newMgef->mgefFlags & EffectSetting::kMgefFlag_UseSkill ) {
		TESComboBox::PopulateWithSkills(cbAV, true);
		TESComboBox::SetCurSelByData(cbAV, (void*)currPtr->actorVal);
	}
	else
		EnableWindow(cbAV, false);
	
	BOOL isSEFF = newMgef->mgefCode == Swap32('SEFF');
	ob = GetDlgItem(hwndDlg, ID_SEFF_SCRIPT);
	EnableWindow(ob, isSEFF);
	TESComboBox::Clear(ob);
	if ( isSEFF ) {
		TESComboBox::PopulateWithScripts(ob, true, false, true);
	}
	ob = GetDlgItem(hwndDlg, IDC_SEFF_NEWSCRIPT);
	EnableWindow(ob, isSEFF);
	SendDlgItemMessage(hwndDlg, IDC_SEFF_NAME, EM_SETREADONLY, !isSEFF, 0);
	ob = GetDlgItem(hwndDlg, ID_SEFF_SCHOOL);
	TESComboBox::Clear(ob);
	if ( isSEFF ) {
		for ( UInt8 i = 0; i < Magic::kSchool__MAX; ++i )
			TESComboBox::AddItem(ob, Magic::GetSchoolName(i), (void*)i);
	}
	EnableWindow(ob, isSEFF);
	ob = GetDlgItem(hwndDlg, ID_SEFF_VIS);
	TESComboBox::Clear(ob);
	if ( isSEFF ) {
		TESComboBox::PopulateWithForms(ob, TESForm::kFormType_EffectSetting, false, true);
	}
	EnableWindow(ob, isSEFF);
	ob = GetDlgItem(hwndDlg, IDC_SEFF_HOSTILE);
	EnableWindow(ob, isSEFF);
	ob = GetDlgItem(hwndDlg, IDC_SEFF_MAG);
	EnableWindow(ob, isSEFF);
	ob = GetDlgItem(hwndDlg, IDC_SEFF_DUR);
	EnableWindow(ob, isSEFF);
	ob = GetDlgItem(hwndDlg, ID_SEFF_BASE);
	EnableWindow(ob, isSEFF);
	ob = GetDlgItem(hwndDlg, ID_SEFF_ENCH);
	EnableWindow(ob, isSEFF);
	ob = GetDlgItem(hwndDlg, ID_SEFF_BARTER);
	EnableWindow(ob, isSEFF);

	return (en?1<<0:0) | ((isSEFF==TRUE)?1<<1:0);
}

void EffectItemGenerator::SetInDialog(HWND hwndDlg) {
	_DMESSAGE("Setting in dialog EffectItemGenerator with MGEF '%s'.", mgef->Name().c_str());

	if ( seff ) { // need to be done first due to how SetEffectSettingInDialog works
		SendDlgItemMessage(hwndDlg, IDC_SEFF_MAG, BM_SETCHECK, (seff->noMag?BST_UNCHECKED:BST_CHECKED), 0);
		SendDlgItemMessage(hwndDlg, IDC_SEFF_DUR, BM_SETCHECK, (seff->noDur?BST_UNCHECKED:BST_CHECKED), 0);
	}

	char buf[4];
	UInt8 mgefResult = SetEffectSettingInDialog(hwndDlg, mgef);

	if ( mgefResult & 1 ) {
		intToStr(minMag) >> buf;
		SendDlgItemMessage(hwndDlg, ID_MINMAG, WM_SETTEXT, 0, (LPARAM)buf);
		
		intToStr(minDur) >> buf;
		SendDlgItemMessage(hwndDlg, ID_MINDUR, WM_SETTEXT, 0, (LPARAM)buf);
		
		intToStr(noDurPct) >> buf;
		SendDlgItemMessage(hwndDlg, ID_NODURPCT, WM_SETTEXT, 0, (LPARAM)buf);
	}
	else {
		buf[0] = 0;

		SendDlgItemMessage(hwndDlg, ID_MINMAG, WM_SETTEXT, 0, (LPARAM)buf);
		SendDlgItemMessage(hwndDlg, ID_MINDUR, WM_SETTEXT, 0, (LPARAM)buf);
		SendDlgItemMessage(hwndDlg, ID_NODURPCT, WM_SETTEXT, 0, (LPARAM)buf);
	}
	
	if ( mgefResult & 2 ) {
		HWND cbScript = GetDlgItem(hwndDlg, ID_SEFF_SCRIPT);
		HWND cbSchool = GetDlgItem(hwndDlg, ID_SEFF_SCHOOL);
		HWND cbVisuals = GetDlgItem(hwndDlg, ID_SEFF_VIS);
		if ( seff ) {
			if ( seff->scriptFormID )
				TESComboBox::SetCurSelByData(cbScript, (void*)TESForm::LookupByFormID(seff->scriptFormID));
			else
				TESComboBox::SetCurSel(cbScript, 0);

			SendDlgItemMessage(hwndDlg, IDC_SEFF_NAME, WM_SETTEXT, 0, (LPARAM)seff->name.c_str());

			TESComboBox::SetCurSelByData(cbSchool, (void*)seff->school);

			TESComboBox::SetCurSelByData(cbVisuals, (void*)EffectSetting::LookupByCode(seff->fxMgefCode));

			SendDlgItemMessage(hwndDlg, IDC_SEFF_HOSTILE, BM_SETCHECK, (seff->hostile?BST_CHECKED:BST_UNCHECKED), 0);

			char floatBuf[16];
			dblToStr(seff->baseCost, 4) >> floatBuf;
			SendDlgItemMessage(hwndDlg, ID_SEFF_BASE, WM_SETTEXT, 0, (LPARAM)floatBuf);

			dblToStr(seff->enchantFactor, 4) >> floatBuf;
			SendDlgItemMessage(hwndDlg, ID_SEFF_ENCH, WM_SETTEXT, 0, (LPARAM)floatBuf);

			dblToStr(seff->barterFactor, 4) >> floatBuf;
			SendDlgItemMessage(hwndDlg, ID_SEFF_BARTER, WM_SETTEXT, 0, (LPARAM)floatBuf);
		}
		else {
			TESComboBox::SetCurSel(cbScript, 0);
			
			buf[0] = 0;
			SendDlgItemMessage(hwndDlg, IDC_SEFF_NAME, WM_SETTEXT, 0, (LPARAM)buf);

			TESComboBox::SetCurSel(cbSchool, 0);

			TESComboBox::SetCurSel(cbVisuals, 0);
			
			SendDlgItemMessage(hwndDlg, IDC_SEFF_HOSTILE, BM_SETCHECK, BST_UNCHECKED, 0);
			SendDlgItemMessage(hwndDlg, IDC_SEFF_MAG, BM_SETCHECK, BST_UNCHECKED, 0);
			SendDlgItemMessage(hwndDlg, IDC_SEFF_DUR, BM_SETCHECK, BST_UNCHECKED, 0);
			
			std::string floatBuf = "0.0000";
			SendDlgItemMessage(hwndDlg, ID_SEFF_BASE, WM_SETTEXT, 0, (LPARAM)floatBuf.c_str());
			SendDlgItemMessage(hwndDlg, ID_SEFF_ENCH, WM_SETTEXT, 0, (LPARAM)floatBuf.c_str());
			SendDlgItemMessage(hwndDlg, ID_SEFF_BARTER, WM_SETTEXT, 0, (LPARAM)floatBuf.c_str());
		}
	}
	else {
		buf[0] = 0;
		SendDlgItemMessage(hwndDlg, IDC_SEFF_NAME, WM_SETTEXT, 0, (LPARAM)buf);
		SendDlgItemMessage(hwndDlg, IDC_SEFF_HOSTILE, BM_SETCHECK, BST_UNCHECKED, 0);
	}

	intToStr(effProp) >> buf;
	SendDlgItemMessage(hwndDlg, ID_EFFPROP, WM_SETTEXT, 0, (LPARAM)buf);

	SendDlgItemMessage(hwndDlg, ID_RANGE, CB_SETCURSEL, (onSelf?0:1), 0);
}

void EffectItemGenerator::SetInListview(HWND dialogHandle, LRESULT sel, UINT dlgItem) {
	LVITEM lv = LVITEM();
	lv.iSubItem = 0;
	UINT msg = 0;
	if ( 0 <= sel && sel < SendDlgItemMessage(dialogHandle, dlgItem, LVM_GETITEMCOUNT, 0, 0) )
		msg = LVM_SETITEM;
	else {
		lv.iItem = SendDlgItemMessage(dialogHandle, dlgItem, LVM_GETITEMCOUNT, 0, 0);
		msg = LVM_INSERTITEM;
	}

	if ( mgef ) {
		lv.mask = LVIF_TEXT | LVIF_PARAM;
		lv.lParam = (LPARAM)this;
		if ( lv.pszText )
			delete [] lv.pszText;
		lv.cchTextMax = 5;
		lv.pszText = new char[5];
		sprintf(lv.pszText, "%4.4s", &(mgef->mgefCode));

		SendDlgItemMessage(dialogHandle, dlgItem, msg, 0, (LPARAM)&lv);
		SendDlgItemMessage(dialogHandle, dlgItem, LVM_UPDATE, lv.iItem, 0);
	}
	else
		_ERROR("MGEF pointer is null.");

	if ( lv.pszText )
		delete [] lv.pszText;
}

INT_PTR CALLBACK EffectItemGenerator::DialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) {
	bool retn = false;
    switch(uMsg) {
		case WM_INITDIALOG: // recieved once, when dialog window is created
		{
			HWND cbMGEF = GetDlgItem(hwndDlg, ID_MGEF);
			if ( !cbMGEF ) {
				DWORD err = GetLastError();
				char* buf = NULL;
				FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_ALLOCATE_BUFFER, 0, err, 0, (LPSTR)&buf, 1<<19, 0);
				_ERROR("GetDlgItem(hwndDlg, ID_MGEF); Error '%s' thrown; control not initialized.", buf);
				LocalFree(buf);
			}
			else
				TESComboBox::PopulateWithForms(cbMGEF, TESForm::kFormType_EffectSetting, false, false);

			SendDlgItemMessage(hwndDlg, ID_RANGE, CB_INITSTORAGE, 2, 2);
			SendDlgItemMessage(hwndDlg, ID_RANGE, CB_ADDSTRING, 0, (LPARAM)"On Self");
			SendDlgItemMessage(hwndDlg, ID_RANGE, CB_ADDSTRING, 0, (LPARAM)"On Target");
			
			currPtr = (EffectItemGenerator*)lParam;
			if ( !currPtr )
				EndDialog(hwndDlg, false);
			if ( !currPtr->mgef )
				currPtr->mgef = DEFF;
			if ( !currPtr->mgef )
				_ERROR("NULL EffectSetting!");
			currPtr->SetInDialog(hwndDlg);
			
			retn = true;
			break;
		}
		
		case WM_COMMAND: // recieved from controls to indicate an action
		{
			WORD lo = wParam & 0xFFFF;
			switch(lo) { // lowest 16 bits of wparam are the control identifier
				case IDOK:  // OK button clicked
				{
					HWND cbMGEF = GetDlgItem(hwndDlg, ID_MGEF);
					if ( TESComboBox::GetCurSelData(cbMGEF) )
						currPtr->mgef = (EffectSetting*)TESComboBox::GetCurSelData(cbMGEF);

					currPtr->onSelf = SendDlgItemMessage(hwndDlg, ID_RANGE, CB_GETCURSEL, 0, 0) == 0;
					
					char buf[4];

					SendDlgItemMessage(hwndDlg, ID_EFFPROP, WM_GETTEXT, 4, (LPARAM)buf);
					currPtr->effProp = strToInt(buf);

					SendDlgItemMessage(hwndDlg, ID_NODURPCT, WM_GETTEXT, 4, (LPARAM)buf);
					currPtr->noDurPct = strToInt(buf);

					currPtr->noAoEPct = 100; // aoe not supported yet.

					SendDlgItemMessage(hwndDlg, ID_MINMAG, WM_GETTEXT, 4, (LPARAM)buf);
					currPtr->minMag = strToInt(buf);

					SendDlgItemMessage(hwndDlg, ID_MINDUR, WM_GETTEXT, 4, (LPARAM)buf);
					currPtr->minDur = strToInt(buf);

					currPtr->minAoE = 0; // aoe not supported yet.

					HWND cbAV = GetDlgItem(hwndDlg, ID_ACTORVAL);
					if ( IsWindowEnabled(cbAV) ) {
						if ( SendDlgItemMessage(hwndDlg, ID_ACTORVAL, CB_GETCURSEL, 0, 0) == 0 )
							currPtr->actorVal = ActorValues::kActorVal__NONE;
						else
							currPtr->actorVal = (UInt8)TESComboBox::GetCurSelData(cbAV);
					}
					else
						currPtr->actorVal = ActorValues::kActorVal__NONE;
					_VMESSAGE("Actor Value set to %i.", currPtr->actorVal);

					
					bool isSEFF = currPtr->mgef->mgefCode == Swap32('SEFF');
					if ( isSEFF ) {
						if ( !currPtr->seff )
							currPtr->seff = new ScriptEffectInfoGenerator;
						if ( currPtr->seff ) {
							HWND cbScript = GetDlgItem(hwndDlg, ID_SEFF_SCRIPT);
							HWND cbSchool = GetDlgItem(hwndDlg, ID_SEFF_SCHOOL);
							HWND cbVisuals = GetDlgItem(hwndDlg, ID_SEFF_VIS);

							TESForm* scriptForm = (TESForm*)TESComboBox::GetCurSelData(cbScript);
							if ( scriptForm )
								currPtr->seff->scriptFormID = scriptForm->formID;
							else
								currPtr->seff->scriptFormID = 0;

							char seffNameBuf[512];
							SendDlgItemMessage(hwndDlg, IDC_SEFF_NAME, WM_GETTEXT, 512, (LPARAM)seffNameBuf);
							currPtr->seff->name.Format("%s", seffNameBuf);

							currPtr->seff->school = (UInt32)TESComboBox::GetCurSelData(cbSchool);

							EffectSetting* fxMgef = (EffectSetting*)TESComboBox::GetCurSelData(cbVisuals);
							if ( fxMgef )
								currPtr->seff->fxMgefCode = fxMgef->mgefCode;
							else
								currPtr->seff->fxMgefCode = 0;

							currPtr->seff->hostile = SendDlgItemMessage(hwndDlg, IDC_SEFF_HOSTILE, BM_GETCHECK, 0, 0) == BST_CHECKED;

							currPtr->seff->noMag = IsDlgButtonChecked(hwndDlg, IDC_SEFF_MAG) == BST_UNCHECKED;
							currPtr->seff->noDur = IsDlgButtonChecked(hwndDlg, IDC_SEFF_DUR) == BST_UNCHECKED;
							currPtr->seff->noAoE = true; //IsDlgButtonChecked(hwndDlg, IDC_SEFF_AOE) == BST_UNCHECKED;

							SendDlgItemMessage(hwndDlg, ID_SEFF_BASE, WM_GETTEXT, 4, (LPARAM)buf);
							currPtr->seff->baseCost = strToDbl(buf);

							SendDlgItemMessage(hwndDlg, ID_SEFF_ENCH, WM_GETTEXT, 4, (LPARAM)buf);
							currPtr->seff->enchantFactor = strToDbl(buf);

							SendDlgItemMessage(hwndDlg, ID_SEFF_BARTER, WM_GETTEXT, 4, (LPARAM)buf);
							currPtr->seff->barterFactor = strToDbl(buf);
						}
					}

					EndDialog(hwndDlg, true);
					return true;
				}
				case IDCANCEL: // Cancel button clicked
					EndDialog(hwndDlg, false);
					return true;

				case IDNOVARS:
					if ( IsDlgButtonChecked(hwndDlg, IDNOVARS) == BST_CHECKED ) {
						SendDlgItemMessage(hwndDlg, ID_NODURPCT, EM_SETREADONLY, TRUE, 0);
						SendDlgItemMessage(hwndDlg, ID_MINMAG, EM_SETREADONLY, TRUE, 0);
						SendDlgItemMessage(hwndDlg, ID_MINDUR, EM_SETREADONLY, TRUE, 0);
					}
					else {
						SendDlgItemMessage(hwndDlg, ID_NODURPCT, EM_SETREADONLY, FALSE, 0);
						SendDlgItemMessage(hwndDlg, ID_MINMAG, EM_SETREADONLY, FALSE, 0);
						SendDlgItemMessage(hwndDlg, ID_MINDUR, EM_SETREADONLY, FALSE, 0);
					}
					retn = true;
					break;

				case ID_MGEF:
					switch(HIWORD(wParam)) {
						case CBN_SELCHANGE:
						{
							HWND cbMGEF = GetDlgItem(hwndDlg, ID_MGEF);
							EffectSetting* newMgef = (EffectSetting*)TESComboBox::GetCurSelData(cbMGEF);
							if ( !newMgef ) {
								_WARNING("Null MGEF choice; resetting.");
								newMgef = currPtr->mgef;
								TESComboBox::SetCurSelByData(cbMGEF, newMgef);
							}
							SetEffectSettingInDialog(hwndDlg, newMgef);
						}
					}
					return false;

				case ID_RANGE:
					switch(HIWORD(wParam)) {
						case CBN_SELCHANGE:
						{
							HWND cbMGEF = GetDlgItem(hwndDlg, ID_MGEF);
							EffectSetting* currMgef = (EffectSetting*)TESComboBox::GetCurSelData(cbMGEF);
							if ( !currMgef ) {
								_WARNING("Null MGEF choice; resetting.");
								currMgef = currPtr->mgef;
								TESComboBox::SetCurSelByData(cbMGEF, currMgef);
							}
							bool en = !((SendDlgItemMessage(hwndDlg, ID_RANGE, CB_GETCURSEL, 0, 0) == 0)
									|| ((currMgef->mgefFlags & EffectSetting::kMgefFlag_NoMagnitude) && !( IsWindowEnabled(GetDlgItem(hwndDlg, IDC_SEFF_MAG)) && IsDlgButtonChecked(hwndDlg, IDC_SEFF_MAG) == BST_CHECKED ))
									|| ((currMgef->mgefFlags & EffectSetting::kMgefFlag_NoDuration) && !( IsWindowEnabled(GetDlgItem(hwndDlg, IDC_SEFF_DUR)) && IsDlgButtonChecked(hwndDlg, IDC_SEFF_DUR) == BST_CHECKED )));

							HWND ob = GetDlgItem(hwndDlg, ID_NODURPCT);
							EnableWindow(ob, en);

							ob = GetDlgItem(hwndDlg, ID_MINMAG);
							EnableWindow(ob, en);

							ob = GetDlgItem(hwndDlg, ID_MINDUR);
							EnableWindow(ob, en);

							return true;
						}
					}
					return false;

				case IDC_SEFF_NEWSCRIPT:
					{
						DWORD Throwaway = 0;
						typedef void (__stdcall *ShowScriptEditorT)(HWND, UINT, WPARAM, LPARAM, LONG);
						((ShowScriptEditorT)0x004A1690)(hwndDlg, uMsg, wParam, lParam, (LONG)&Throwaway);
					}
					return true;
					
				case IDC_SEFF_MAG:
				case IDC_SEFF_DUR:
					{
						bool en = ((SendDlgItemMessage(hwndDlg, ID_RANGE, CB_GETCURSEL, 0, 0) == 1)
								&& (IsWindowEnabled(GetDlgItem(hwndDlg, IDC_SEFF_MAG)) && IsDlgButtonChecked(hwndDlg, IDC_SEFF_MAG) == BST_CHECKED)
								&& (IsWindowEnabled(GetDlgItem(hwndDlg, IDC_SEFF_DUR)) && IsDlgButtonChecked(hwndDlg, IDC_SEFF_DUR) == BST_CHECKED));

						HWND ob = GetDlgItem(hwndDlg, ID_NODURPCT);
						EnableWindow(ob, en);

						ob = GetDlgItem(hwndDlg, ID_MINMAG);
						EnableWindow(ob, en);

						ob = GetDlgItem(hwndDlg, ID_MINDUR);
						EnableWindow(ob, en);
					}
					return true;
			}
			break;
		}

		case WM_DESTROY:
			retn = true;
			break;
	}
	ShowWindow(hwndDlg, SW_SHOWNORMAL);
	return retn;
}
#endif
